header {
package com.hermeneute.fsa.parser;
}

{
import java.util.*;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.StringReader;
import java.util.Hashtable;
import antlr.CharScanner;
import antlr.TokenStreamRecognitionException;
import antlr.SemanticException;

}
class FSTParserTree extends Parser;

options {
    k=6; // needed for newline junk
    defaultErrorHandler = false;
    buildAST = true;   // uses CommonAST by default
}

{	
    int line = 0;
    int sn = 0;
	Set errors = new HashSet();
	Set automata = new HashSet();
	public void init() {
		astFactory.setASTNodeClass(TokenAST.class);
	}
	void addError(Exception e){
		errors.add(e);
	}
	public void clearErrors(){
		errors.clear();
	}
	public Set getErrors() {
		return errors;
	}
	public Set getAutomata() {
		return automata;
	}
	public int getNumberOfStatement() {
		return sn;
	}
	public int getLine() {
		return line;
	}
}


file : 
 statement {
		if (getAST() != null) {
			line = ((TokenAST)getAST()).getToken().getLine();
		sn++; 
		}
 	}
 (statement {
 		if (getAST() != null) {
			line = ((TokenAST)getAST()).getToken().getLine();
		sn++; 
		}
 	})* EOF
	;
    exception
    catch [TokenStreamRecognitionException ex] {
    	//System.err.println("Caught TokenStreamRecognitionException in file");
	    addError(ex); 
	    if ( $FOLLOW.member(SC) ) {
        	consumeUntil(SC);
    	}
   		 else {
        	consume();
    	}
    }
    catch [TokenStreamIOException ex] {
    	//System.err.println("Caught TokenStreamIOException in file");
    	addError(ex); 
	    if ( $FOLLOW.member(SC) ) {
        	consumeUntil(SC);
    	}
   		 else {
        	consume();
    	}
    }
    catch [SemanticException ex] {
    	//System.err.println("Caught SemanticException in file");
    	addError(ex); 
	    if ( $FOLLOW.member(SC) ) {
        	consumeUntil(SC);
    	}
   		 else {
        	consume();
    	}
    }
    catch [RecognitionException ex] {
    	//System.err.println("Caught RecognitionException in file");
    	addError(ex); 
	    if ( $FOLLOW.member(SC) ) {
        	consumeUntil(SC);
    	}
   		 else {
        	consume();
    	}
    }
    catch [Exception ex] {
    	ex.printStackTrace();
    	addError(ex); 
	    if ( $FOLLOW.member(SC) ) {
        	consumeUntil(SC);
    	}
   		 else {
        	consume();
    	}
    }

statement 
	: s:SYMBOL^ {automata.add(s.getText());} EQ (expression | READ STRING) SC
    | WRITE^  expression TO STRING SC
  	| PRINT^  expression SC
	| INSERT^ STRING INTO expression SC
	| AUTOMATON^ EQ COMPILE  SYMBOL SC
	| PARSE^ AUTOMATON FILE STRING SC
	| PARSE^ AUTOMATON STRING SC
	| SL_COMMENTS^ WS
	;
    exception // for rule
    catch [TokenStreamRecognitionException ex] {
    	//System.err.println("Caught TokenStreamRecognitionException in statement");
	    addError(ex); 
	    if ( $FOLLOW.member(SC) ) {
        	consumeUntil(SC);
    	}
   		 else {
        	consume();
    	}
    }
    catch [RecognitionException ex] {
    	//System.err.println("Caught RecognitionException in statement");
	    addError(ex); 
	    if ( $FOLLOW.member(SC) ) {
        	consumeUntil(SC);
    	}
   		 else {
        	consume();
    	}
    }

expression 
	: intersectionExpression
	;

intersectionExpression 
	: unionExpression (AND unionExpression)*
	;

unionExpression	
	: productExpression (UNION productExpression)*
	;

productExpression
	: subExpression (subExpression)*
	;


subExpression 
	: atomicExpression   (PLUS | QUESTION | STAR )?
	| parenthesisExpression  (PLUS | QUESTION | STAR )?
	;

parenthesisExpression
	: LPAR expression  RPAR
	| NOT LPAR expression RPAR
	;


			
atomicExpression 
	: atomicExpressionU
	| atomicExpressionP
	| var
	;

var 
	: SYMBOL
	;

string 
	: STRING
	;

atomicExpressionU 
	: ANY
	| ZERO COL 
	;


atomicExpressionP
	: string
	  (COL ZERO)?  
	;

class FSTLexerTree extends Lexer;

options {
    k=4; // needed for newline junk
    charVocabulary='\u0000'..'\uFFFF'; // allow ascii
}
{	
	public void setTokenObjectClass(String cl) {
		try {
			tokenObjectClass = Class.forName(cl);
		}
		catch (ClassNotFoundException ce) {
			panic("ClassNotFoundException1: "+cl);
		}
	}
}
COMPILE
	: "compile"
	;

PARSE
	: "parse"
	;

FILE
	: "file"
	;

INSERT
	: "insert"
	;

INTO
	: "into"
	;

TO
	: ">>"
	;

READ
	: "read"
	;

PRINT
	: "print"
	;

WRITE
	: "write"
	;

LT
	: '<'
	;

GT
	: '>'
	;

SC
	: ';'
	;

EQ
	: '='
	;

PLUS
	: '+'
	;

QUESTION
	: '?'
	;

STAR
	: '*'
	;

NOT
	: '^'
	;

LPAR
	: '('
	;

RPAR
	: ')'
	;

LSET
	: '['
	;

RSET
	: ']'
	;

PERC
	: '%'
	;

UNION
	: '|'
	;

AND
	: '&'
	;

COL
	: ':'
	;

ANY	
	: '@'
	;

ZERO
	: '0'
	;

SYMBOL
	: '<' (('a' .. 'z')|('A' .. 'Z')| '_')(('a' .. 'z')|('A' .. 'Z')| ('0' .. '9') | '_')* '>' 
	;

AUTOMATON
	: '[' (('a' .. 'z')|('A' .. 'Z')| '_')(('a' .. 'z')|('A' .. 'Z')| ('0' .. '9') | '_')* ']' 
	;


	// Whitespace -- ignored
WS	:	(	' '
		|	'\t'
		|	'\f'
				// handle newlines
		|	(	options {generateAmbigWarnings=false;}
				:	"\r\n"  // Evil DOS
				|	'\r'    // Macintosh
				|	'\n'    // Unix (the right way)
				)
				{ newline(); }
		)+
		{ _ttype = Token.SKIP; }
	;

STRING
	: '"'! ( ESCAPE | ~('"'|'\\') )* '"'! 
	;


SL_COMMENT
	:	"#"
		(~('\n'|'\r'))* ('\n'|'\r'('\n')?)
		{$setType(Token.SKIP); newline();}
	;

protected
ESCAPE
    :    '\\'
         ( 'n' { $setText("\n"); }
         | 'r' { $setText("\r"); }
         | 't' { $setText("\t"); }
         | '"' { $setText("\""); }
         | '\\' { $setText("\\"); }
         )
    ;




